package org.piwicode.bywordofmouth.ui;

import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.googlecode.cqengine.IndexedCollection;
import static com.googlecode.cqengine.query.QueryFactory.contains;
import com.googlecode.cqengine.resultset.ResultSet;
import org.piwicode.bywordofmouth.FileResource;
import org.piwicode.bywordofmouth.Resource;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingWorker;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.AbstractTableModel;

/**
 *
 * @author pierre
 */
public class SimpleSearch extends javax.swing.JFrame {

    private final IndexedCollection<Resource> resources;
    final ExecutorService es = Executors.newSingleThreadExecutor();
    final ResultSetTreeModel model;

    /**
     * Creates new form SimpleSearch
     */
    public SimpleSearch(final IndexedCollection<Resource> resources) {
        this.resources = Preconditions.checkNotNull(resources);
        model = new ResultSetTreeModel();
        initComponents();
        jTextField1.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                search(jTextField1.getText());
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                search(jTextField1.getText());
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
            }
        });
    }

    private void search(final String text) {
        es.execute(new SwingWorker<List<Resource>, Void>() {
            @Override
            protected List<Resource> doInBackground() throws Exception {
                if (text.isEmpty())
                    return Collections.emptyList();
                final String search = FileResource.normalize(text);
                final ResultSet<Resource> rs = resources.retrieve(contains(FileResource.NAME, search));
                return Lists.newArrayList(Iterables.limit(rs, 256));
            }

            @Override
            protected void done() {
                try {
                    model.setResultSet(get());
                } catch (InterruptedException ex) {
                    Logger.getLogger(SimpleSearch.class.getName()).log(Level.SEVERE, null, ex);
                } catch (ExecutionException ex) {
                    Logger.getLogger(SimpleSearch.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jTextField1 = new javax.swing.JTextField();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTable1 = new javax.swing.JTable();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jTextField1.setText("jTextField1");
        getContentPane().add(jTextField1, java.awt.BorderLayout.PAGE_START);

        jTable1.setModel(model);
        jScrollPane1.setViewportView(jTable1);

        getContentPane().add(jScrollPane1, java.awt.BorderLayout.CENTER);

        pack();
    }// </editor-fold>//GEN-END:initComponents

    /**
     * @param args the command line arguments
     */
    public static void go(final IndexedCollection<Resource> resources) throws InterruptedException, InvocationTargetException {

        java.awt.EventQueue.invokeAndWait(new Runnable() {
            public void run() {
                new SimpleSearch(resources).setVisible(true);
            }
        });

    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTable jTable1;
    private javax.swing.JTextField jTextField1;
    // End of variables declaration//GEN-END:variables

    private static class ResultSetTreeModel extends AbstractTableModel {

        List<Resource> list = new ArrayList<Resource>();

        public ResultSetTreeModel() {
        }

        @Override
        public int getRowCount() {
            return list.size();
        }

        @Override
        public int getColumnCount() {
            return 3;
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            switch (columnIndex) {
                case 0:
                    return list.get(rowIndex).toString();
                case 1:
                    return list.get(rowIndex).length();
                default:
                    return list.get(rowIndex).lastModified();

            }
        }

        private void setResultSet(List<Resource> get) {
            list = get;

            fireTableDataChanged();

        }
    }

    class MemoizeResultSet extends ResultSet<Resource> {

        ResultSet<Resource> rs;
        int size;

        public MemoizeResultSet(ResultSet<Resource> rs) {
            this.rs = rs;
            size = rs.size();
        }

        @Override
        public Iterator<Resource> iterator() {
            return rs.iterator();
        }

        @Override
        public boolean contains(Resource o) {
            return rs.contains(o);
        }

        @Override
        public Resource uniqueResult() {
            return rs.uniqueResult();
        }

        @Override
        public int getRetrievalCost() {
            return rs.getRetrievalCost();
        }

        @Override
        public int getMergeCost() {
            return rs.getMergeCost();
        }

        @Override
        public int size() {
            return size;
        }
    }
}
